/*
 * Copyright (c) [2020], MediaTek Inc. All rights reserved.
 *
 * This software/firmware and related documentation ("MediaTek Software") are
 * protected under relevant copyright laws.
 * The information contained herein is confidential and proprietary to
 * MediaTek Inc. and/or its licensors.
 * Except as otherwise provided in the applicable licensing terms with
 * MediaTek Inc. and/or its licensors, any reproduction, modification, use or
 * disclosure of MediaTek Software, and information contained herein, in whole
 * or in part, shall be strictly prohibited.
*/
/*
 ***************************************************************************
 ***************************************************************************

    Module Name:
    sta_ioctl.c

    Abstract:
    IOCTL related subroutines

    Revision History:
    Who         When          What
    --------    ----------    ----------------------------------------------
    Rory Chen   01-03-2003    created
	Rory Chen   02-14-2005    modify to support RT61
*/

#define RTMP_MODULE_OS

#include "rtmp_comm.h"
#include "rt_os_util.h"
#include "rt_os_net.h"
/*#include	"rt_config.h" */

#ifdef DBG
extern int   DebugLevel;
extern UINT32 DebugCategory;
extern UINT32 DebugSubCategory[DBG_LVL_MAX + 1][32];
#endif

#define NR_WEP_KEYS				4
#define WEP_SMALL_KEY_LEN			(40/8)
#define WEP_LARGE_KEY_LEN			(104/8)

#define GROUP_KEY_NO                4

#if (KERNEL_VERSION(2, 6, 27) <= LINUX_VERSION_CODE)
#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E)		iwe_stream_add_event(_A, _B, _C, _D, _E)
#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E)		iwe_stream_add_point(_A, _B, _C, _D, _E)
#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F)	iwe_stream_add_value(_A, _B, _C, _D, _E, _F)
#else
#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E)		iwe_stream_add_event(_B, _C, _D, _E)
#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E)		iwe_stream_add_point(_B, _C, _D, _E)
#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F)	iwe_stream_add_value(_B, _C, _D, _E, _F)
#endif

extern UCHAR    CipherWpa2Template[];

typedef struct GNU_PACKED _RT_VERSION_INFO {
	UCHAR       DriverVersionW;
	UCHAR       DriverVersionX;
	UCHAR       DriverVersionY;
	UCHAR       DriverVersionZ;
	UINT        DriverBuildYear;
	UINT        DriverBuildMonth;
	UINT        DriverBuildDay;
} RT_VERSION_INFO, *PRT_VERSION_INFO;

struct iw_priv_args privtab[] = {
	{
		RTPRIV_IOCTL_SET,
		IW_PRIV_TYPE_CHAR | 1024, 0,
		"set"
	},
	{
		RTPRIV_IOCTL_STA_SHOW, /* snowpin for ap/sta */
		IW_PRIV_TYPE_CHAR | 1024, 0,
		"show"
	},

	{
		RTPRIV_IOCTL_SUBCMD_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK,
		""
	},
	/* --- sub-ioctls definitions --- */
#ifdef MAT_SUPPORT
	{
		SHOW_IPV4_MAT_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "ipv4_matinfo"
	},
	{
		SHOW_IPV6_MAT_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "ipv6_matinfo"
	},
	{
		SHOW_ETH_CLONE_MAC,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "cloneMAC"
	},
#endif /* MAT_SUPPORT */
	{
		SHOW_CONN_STATUS,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus"
	},
	{
		SHOW_DRVIER_VERION,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer"
	},
	{
		SHOW_BA_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo"
	},
	{
		SHOW_DESC_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo"
	},
	{
		RAIO_OFF,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off"
	},
	{
		RAIO_ON,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on"
	},
	{
		SHOW_CFG_VALUE,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show"
	},
	{
		SHOW_ADHOC_ENTRY_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry"
	},
#if defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT)
	{
		SHOW_TDLS_ENTRY_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "tdlsentryinfo"
	},
#endif /* defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT) */
	{
		SHOW_DEV_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "devinfo"
	},
	{
		SHOW_STA_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "stainfo"
	},
	{
		SHOW_TR_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "trinfo"
	},
	{
		SHOW_SYS_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "sysinfo"
	},
	{
		SHOW_PWR_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "pwrinfo"
	},
	{
		SHOW_DIAGNOSE_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "diaginfo"
	},
#ifdef MT_MAC
	{
		SHOW_WTBL_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "wtbl"
	},
	{
		SHOW_MIB_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mibinfo"
	},
	{
		SHOW_TMAC_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "tmacinfo"
	},
	{
		SHOW_AGG_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "agginfo"
	},
	{
		SHOW_PSE_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "pseinfo"
	},
	{
		SHOW_PLE_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "pleinfo"
	},
	{
		SHOW_TXD_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "txdinfo"
	},
	{
		DUMP_MEM_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dumpmem"
	},
	{
		SHOW_PSE_DATA,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "psedata"
	},
#ifdef DMA_SCH_SUPPORT
	{
		SHOW_DSCH_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dschinfo"
	},
#endif
#ifdef CUT_THROUGH
	{
		SHOW_CT_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "ctinfo"
	},
#endif /* CUT_THROUGH */
#ifdef DBDC_MODE
	{
		SHOW_DBDC_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dbdcinfo"
	},
#endif /*DBDC_MODE*/
	{
		SHOW_TXOP_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "txopinfo"
	},
#endif /* MT_MAC */
#ifdef MEM_ALLOC_INFO_SUPPORT
	{
		SHOW_MEM_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "meminfo"
	},
	{
		SHOW_PKTMEM_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "pktmeminfo"
	},
#endif /* MEM_ALLOC_INFO_SUPPORT */
	{
		SHOW_WIFI_INT_CNT,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "wfintcnt"
	},
	{
		SHOW_EFUSE_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuseinfo"
	},
	{
		SHOW_E2P_INFO,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "e2pinfo"
	},

	/* --- sub-ioctls relations --- */

#ifdef DBG
	{
		RTPRIV_IOCTL_BBP,
		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK,
		"bbp"
	},
	{
		RTPRIV_IOCTL_MAC,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024,
		"mac"
	},
#ifdef RTMP_RF_RW_SUPPORT
	{
		RTPRIV_IOCTL_RF,
		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK,
		"rf"
	},
#endif /* RTMP_RF_RW_SUPPORT */
	{
		RTPRIV_IOCTL_E2P,
		IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024,
		"e2p"
	},
#endif  /* DBG */

	{
		RTPRIV_IOCTL_STATISTICS,
		0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK,
		"stat"
	},
	{
		RTPRIV_IOCTL_GSITESURVEY,
		0, IW_PRIV_TYPE_CHAR | 1024,
		"get_site_survey"
	},

#ifdef WSC_STA_SUPPORT
	{
		RTPRIV_IOCTL_SET_WSC_PROFILE_U32_ITEM,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""
	},
	{
		RTPRIV_IOCTL_SET_WSC_PROFILE_U32_ITEM,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, ""
	},
	{
		RTPRIV_IOCTL_SET_WSC_PROFILE_STRING_ITEM,
		IW_PRIV_TYPE_CHAR | 128, 0, ""
	},
	/* --- sub-ioctls definitions --- */
	{
		WSC_CREDENTIAL_COUNT,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wsc_cred_count"
	},
	{
		WSC_CREDENTIAL_SSID,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_cred_ssid"
	},
	{
		WSC_CREDENTIAL_AUTH_MODE,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_cred_auth"
	},
	{
		WSC_CREDENTIAL_ENCR_TYPE,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_cred_encr"
	},
	{
		WSC_CREDENTIAL_KEY_INDEX,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_cred_keyIdx"
	},
	{
		WSC_CREDENTIAL_KEY,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_cred_key"
	},
	{
		WSC_CREDENTIAL_MAC,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_cred_mac"
	},
	{
		WSC_SET_DRIVER_CONNECT_BY_CREDENTIAL_IDX,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wsc_conn_by_idx"
	},
	{
		WSC_SET_DRIVER_AUTO_CONNECT,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wsc_auto_conn"
	},
	{
		WSC_SET_CONF_MODE,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wsc_conf_mode"
	},
	{
		WSC_SET_MODE,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wsc_mode"
	},
	{
		WSC_SET_PIN,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_pin"
	},
	{
		WSC_SET_SSID,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_ssid"
	},
	{
		WSC_SET_BSSID,
		IW_PRIV_TYPE_CHAR | 128, 0, "wsc_bssid"
	},
	{
		WSC_START,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "wsc_start"
	},
	{
		WSC_STOP,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "wsc_stop"
	},
	{
		WSC_GEN_PIN_CODE,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "wsc_gen_pincode"
	},
	{
		WSC_AP_BAND,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wsc_ap_band"
	},
	/* --- sub-ioctls relations --- */
#endif /* WSC_STA_SUPPORT */
#ifdef WCX_SUPPORT
	{
		MTPRIV_IOCTL_META_SET,
		IW_PRIV_TYPE_CHAR | 1024, 0,
		"meta_set"
	},
	{
		MTPRIV_IOCTL_META_QUERY,
		IW_PRIV_TYPE_CHAR | 1024, 0,
		"meta_query"
	},
#endif /* WCX_SUPPORT */
#ifdef REDUCE_TCP_ACK_SUPPORT
	{
		SHOW_TCP_RACK_INFO,
		IW_PRIV_TYPE_CHAR | 1024,
		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "ReduceAckShow"
	},
#endif
};

extern INT32 ralinkrate[];
extern UINT32 RT_RateSize;

INT DetermineCallerInterface(struct net_device *net_dev, VOID *pAd)
{
	RT_CMD_IOCTL_INTERFACE_CONFIG   IoctlConfig, *pIoctlConfig = &IoctlConfig;
	/* Determine the interface idx */
	pIoctlConfig->Status = 0;
	pIoctlConfig->net_dev = net_dev;
	pIoctlConfig->wdev = RTMP_OS_NETDEV_GET_WDEV(net_dev);
	pIoctlConfig->priv_flags = RT_DEV_PRIV_FLAGS_GET(net_dev);
	pIoctlConfig->name = net_dev->name;
	pIoctlConfig->interface_idx = 0;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_PREPARE, 0,
							 pIoctlConfig, 0, RT_DEV_PRIV_FLAGS_GET(net_dev)) != NDIS_STATUS_SUCCESS) {
		/* prepare error */
		return -EFAULT;
	}

	return NDIS_STATUS_SUCCESS;
}


/* This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function */
int rt_ioctl_giwname(struct net_device *dev,
					 struct iw_request_info *info,
					 char *name, char *extra)
{
	strncpy(name, "Ralink STA", IFNAMSIZ);
	return 0;
}

int rt_ioctl_siwfreq(struct net_device *dev,
					 struct iw_request_info *info,
					 struct iw_freq *freq, char *extra)
{
	VOID *pAd = NULL;
	/*	int	chan = -1; */
	RT_CMD_STA_IOCTL_FREQ IoctlFreq, *pIoctlFreq = &IoctlFreq;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(NULL, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (freq->e > 1)
		return -EINVAL;

	pIoctlFreq->m = freq->m;
	pIoctlFreq->e = freq->e;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWFREQ, 0,
							 pIoctlFreq, 0, RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS)
		return -EINVAL;

	return 0;
}


int rt_ioctl_giwfreq(struct net_device *dev,
					 struct iw_request_info *info,
					 struct iw_freq *freq, char *extra)
{
	VOID *pAd = NULL;
	ULONG	m = 2412000;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(NULL, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWFREQ, 0,
						 &m, RT_DEV_PRIV_FLAGS_GET(dev), RT_DEV_PRIV_FLAGS_GET(dev));
	freq->m = m * 100;
	freq->e = 1;
	freq->i = 0;
	return 0;
}


int rt_ioctl_siwmode(struct net_device *dev,
					 struct iw_request_info *info,
					 __u32 *mode, char *extra)
{
	VOID *pAd = NULL;
	LONG Mode;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (*mode == IW_MODE_ADHOC)
		Mode = RTMP_CMD_STA_MODE_ADHOC;
	else if (*mode == IW_MODE_INFRA)
		Mode = RTMP_CMD_STA_MODE_INFRA;

#if (KERNEL_VERSION(2, 4, 20) < LINUX_VERSION_CODE)
	else if (*mode == IW_MODE_MONITOR)
		Mode = RTMP_CMD_STA_MODE_MONITOR;

#endif /* LINUX_VERSION_CODE */
	else {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode);
		return -EINVAL;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWMODE, 0,
						 NULL, Mode, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}


int rt_ioctl_giwmode(struct net_device *dev,
					 struct iw_request_info *info,
					 __u32 *mode, char *extra)
{
	VOID *pAd = NULL;
	ULONG Mode = 0;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL)
		return -ENETDOWN;

	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWMODE, 0,
						 &Mode, 0, RT_DEV_PRIV_FLAGS_GET(dev));

	if (Mode == RTMP_CMD_STA_MODE_ADHOC)
		*mode = IW_MODE_ADHOC;
	else if (Mode == RTMP_CMD_STA_MODE_INFRA)
		*mode = IW_MODE_INFRA;

#if (KERNEL_VERSION(2, 4, 20) < LINUX_VERSION_CODE)
	else if (Mode == RTMP_CMD_STA_MODE_MONITOR) {
		*mode = IW_MODE_MONITOR;
#define RADIOTAP_TYPE 0
#define PRISM_TYPE 1

		if (get_sniffer_mode(dev) == RADIOTAP_TYPE)
			dev->type = ARPHRD_IEEE80211_RADIOTAP;

		if (get_sniffer_mode(dev) == PRISM_TYPE)
			dev->type = ARPHRD_IEEE80211_PRISM;
	}

#endif /* LINUX_VERSION_CODE */
	else
		*mode = IW_MODE_AUTO;

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "==>rt_ioctl_giwmode(mode=%d)\n", *mode);
	return 0;
}

int rt_ioctl_siwsens(struct net_device *dev,
					 struct iw_request_info *info,
					 char *name, char *extra)
{
	VOID *pAd = NULL;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/* if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	return 0;
}

int rt_ioctl_giwsens(struct net_device *dev,
					 struct iw_request_info *info,
					 char *name, char *extra)
{
	return 0;
}

int rt_ioctl_giwrange(struct net_device *dev,
					  struct iw_request_info *info,
					  struct iw_point *data, char *extra)
{
	VOID *pAd = NULL;
	struct iw_range *range = (struct iw_range *) extra;
	UINT16 val;
	int i;
	ULONG Mode = 0, ChannelListNum = 0;
	UCHAR *pChannel;
	UINT32 *pFreq;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT
#ifndef RT_CFG80211_SUPPORT

	/*if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

#endif /* RT_CFG80211_SUPPORT */
#endif /* NATIVE_WPA_SUPPLICANT_SUPPORT */
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "===>rt_ioctl_giwrange\n");
	data->length = sizeof(struct iw_range);
	memset(range, 0, sizeof(struct iw_range));
	range->txpower_capa = IW_TXPOW_DBM;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWMODE, 0,
						 &Mode, 0, RT_DEV_PRIV_FLAGS_GET(dev));

	/*	if (INFRA_ON(pAd)||ADHOC_ON(pAd)) */
	if ((Mode == RTMP_CMD_STA_MODE_INFRA) || (Mode == RTMP_CMD_STA_MODE_ADHOC)) {
		range->min_pmp = 1 * 1024;
		range->max_pmp = 65535 * 1024;
		range->min_pmt = 1 * 1024;
		range->max_pmt = 1000 * 1024;
		range->pmp_flags = IW_POWER_PERIOD;
		range->pmt_flags = IW_POWER_TIMEOUT;
		range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT |
						 IW_POWER_UNICAST_R | IW_POWER_ALL_R;
	}

	range->we_version_compiled = WIRELESS_EXT;
	range->we_version_source = 14;
	range->retry_capa = IW_RETRY_LIMIT;
	range->retry_flags = IW_RETRY_LIMIT;
	range->min_retry = 0;
	range->max_retry = 255;

	/*	range->num_channels =  pAd->ChannelListNum; */

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_CHAN_LIST_NUM_GET, 0,
						 &ChannelListNum, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	range->num_channels = ChannelListNum;
	os_alloc_mem(NULL, (UCHAR **)&pChannel, sizeof(UCHAR)*ChannelListNum);

	if (pChannel == NULL)
		return -ENOMEM;

	os_alloc_mem(NULL, (UCHAR **)&pFreq, sizeof(UINT32)*ChannelListNum);

	if (pFreq == NULL) {
		os_free_mem(pChannel);
		return -ENOMEM;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_CHAN_LIST_GET, 0,
						 pChannel, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_FREQ_LIST_GET, 0,
						 pFreq, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	val = 0;

	for (i = 1; i <= range->num_channels && i < IW_MAX_FREQUENCIES; i++) {
		/*		UINT32 m = 2412000; */
		range->freq[val].i = pChannel[i - 1];
		/*		MAP_CHANNEL_ID_TO_KHZ(pAd->ChannelList[i-1].Channel, m); */
		range->freq[val].m = pFreq[i - 1] * 100; /* OS_HZ */
		range->freq[val].e = 1;
		val++;

		if (val == IW_MAX_FREQUENCIES)
			break;
	}

	os_free_mem(pChannel);
	os_free_mem(pFreq);
	range->num_frequency = val;
	/* what is correct max? This was not documented exactly. At least 69 has been observed. */
	range->max_qual.qual = 100;
	range->max_qual.level = 0; /* dB */
	range->max_qual.noise = 0; /* dB */
	/* What would be suitable values for "average/typical" qual? */
	range->avg_qual.qual = 20;
	range->avg_qual.level = -60;
	range->avg_qual.noise = -95;
	range->sensitivity = 3;
	range->max_encoding_tokens = NR_WEP_KEYS;
	range->num_encoding_sizes = 2;
	range->encoding_size[0] = 5;
	range->encoding_size[1] = 13;
	range->min_rts = 0;
	range->max_rts = 2347;
	range->min_frag = 256;
	range->max_frag = 2346;
#if WIRELESS_EXT > 17
	/* IW_ENC_CAPA_* bit field */
	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
					  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
#endif
	return 0;
}

int rt_ioctl_giwpriv(
	struct net_device *dev,
	struct iw_request_info *info,
	struct iw_point *dwrq,	char *extra)
{
#ifdef ANDROID_SUPPORT
	VOID *pAd = NULL;
	int len = 0;
	char *ext;
	int ret = 0;

	len = dwrq->length;
	os_alloc_mem(NULL, (UCHAR **)&ext, len);

	if (!ext)
		return -ENOMEM;

	if (copy_from_user(ext, dwrq->pointer, len)) {
		os_free_mem(ext);
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "andriod_handle_private   copy_from_user\n");
		return -EFAULT;
	}

	ext[len - 1] = 0x00;
	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	if (rtstrcasecmp(ext, "START") == TRUE) {
		/* Turn on Wi-Fi hardware */
		/* OK if successful */
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "sSTART Turn on Wi-Fi hardware\n");
		os_free_mem(ext);
		return -1;
	} else if (rtstrcasecmp(ext, "STOP") == TRUE) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "STOP Turn off  Wi-Fi hardware\n");
		os_free_mem(ext);
		return -1;
	} else if (rtstrcasecmp(ext, "RSSI") == TRUE) {
		CHAR AvgRssi0;

		RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWPRIVRSSI,
							 0, &AvgRssi0, 0, dev->priv_flags);
		snprintf(ext, min(dwrq->length, (UINT16)(strlen(ext) + 1)), "rssi %d", AvgRssi0);
	} else if (rtstrcasecmp(ext, "LINKSPEED") == TRUE)
		snprintf(ext, min(dwrq->length, (UINT16)(strlen(ext) + 1)), "LINKSPEED %d", 150);
	else if (rtstrcasecmp(ext, "MACADDR") == TRUE) {
		UCHAR mac[6];

		RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIFHWADDR,
							 0, mac, 0, dev->priv_flags);
		snprintf(ext, min(dwrq->length, (UINT16)(strlen(ext) + 1)),
				 "MACADDR = %02x.%02x.%02x.%02x.%02x.%02x",
				 mac[0], mac[1], mac[2],
				 mac[3], mac[4], mac[5]);
	} else if (rtstrcasecmp(ext, "SCAN-ACTIVE") == TRUE)
		snprintf(ext, min(dwrq->length, (UINT16)(strlen(ext) + 1)), "OK");
	else if (rtstrcasecmp(ext, "SCAN-PASSIVE") == TRUE)
		snprintf(ext, min(dwrq->length, (UINT16)(strlen(ext) + 1)), "OK");
	else
		goto FREE_EXT;

	if (copy_to_user(dwrq->pointer, ext, min(dwrq->length, (UINT16)(strlen(ext) + 1))))
		ret = -EFAULT;

FREE_EXT:
	os_free_mem(ext);
	return ret;
#else
	return 0;
#endif
}


int rt_ioctl_siwap(struct net_device *dev,
				   struct iw_request_info *info,
				   struct sockaddr *ap_addr, char *extra)
{
	VOID *pAd = NULL;
	UCHAR Bssid[6];

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}


	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWAP, 0,
						 (VOID *)(ap_addr->sa_data), 0, RT_DEV_PRIV_FLAGS_GET(dev));
	memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN);
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "IOCTL::SIOCSIWAP "MACSTR"\n",
			 MAC2STR(Bssid));
	return 0;
}

int rt_ioctl_giwap(struct net_device *dev,
				   struct iw_request_info *info,
				   struct sockaddr *ap_addr, char *extra)
{
	VOID *pAd = NULL;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}


	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWAP, 0,
							 (VOID *)(ap_addr->sa_data), 0,
							 RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "IOCTL::SIOCGIWAP(=EMPTY)\n");
		return -ENOTCONN;
	}

	ap_addr->sa_family = ARPHRD_ETHER;
	return 0;
}

/*
 * Units are in db above the noise floor. That means the
 * rssi values reported in the tx/rx descriptors in the
 * driver are the SNR expressed in db.
 *
 * If you assume that the noise floor is -95, which is an
 * excellent assumption 99.5 % of the time, then you can
 * derive the absolute signal level (i.e. -95 + rssi).
 * There are some other slight factors to take into account
 * depending on whether the rssi measurement is from 11b,
 * 11g, or 11a.   These differences are at most 2db and
 * can be documented.
 *
 * NB: various calculations are based on the orinoco/wavelan
 *     drivers for compatibility
 */
static void set_quality(VOID *pAd,
						struct iw_quality *iq,
						RT_CMD_STA_IOCTL_BSS *pBss)
/*                        BSS_ENTRY *pBssEntry) */
{
	iq->qual = pBss->ChannelQuality;
	iq->level = (__u8)(pBss->Rssi);
	iq->noise = pBss->Noise;
	/*    iq->updated = pAd->iw_stats.qual.updated; */
	/*	iq->updated = ((struct iw_statistics *)(pAd->iw_stats))->qual.updated; */
	/* iq->updated = 1; */    /* Flags to know if updated */
#if WIRELESS_EXT >= 17
	iq->updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED;
#endif
#if WIRELESS_EXT >= 19
	iq->updated |= IW_QUAL_DBM;	/* Level + Noise are dBm */
#endif
}

int rt_ioctl_iwaplist(struct net_device *dev,
					  struct iw_request_info *info,
					  struct iw_point *data, char *extra)
{
	VOID *pAd = NULL;
	/*	struct sockaddr addr[IW_MAX_AP]; */
	struct sockaddr *addr = NULL;
	struct iw_quality qual[IW_MAX_AP];
	int i;
	RT_CMD_STA_IOCTL_BSS_LIST BssList, *pBssList = &BssList;
	RT_CMD_STA_IOCTL_BSS *pList;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	memset(qual, 0, sizeof(qual));

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		data->length = 0;
		return 0;
		/*return -ENETDOWN; */
	}

	/* allocate memory */
	os_alloc_mem(NULL, (UCHAR **) &(pBssList->pList), sizeof(RT_CMD_STA_IOCTL_BSS) * IW_MAX_AP);

	if (pBssList->pList == NULL) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "Allocate memory fail!!!\n");
		return 0;
	}
	memset(pBssList->pList, 0, sizeof(RT_CMD_STA_IOCTL_BSS) * IW_MAX_AP);

	os_alloc_mem(NULL, (UCHAR **)&addr, sizeof(struct sockaddr) * IW_MAX_AP);

	if (addr == NULL) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "Allocate memory fail!!!\n");
		os_free_mem(pBssList->pList);
		return 0;
	}
	memset(addr, 0, sizeof(struct sockaddr) * IW_MAX_AP);

	pBssList->MaxNum = IW_MAX_AP;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS) {
		os_free_mem(addr);
		os_free_mem(pBssList->pList);
		return -EFAULT;
	}

	NdisZeroMemory(pBssList, sizeof(RT_CMD_STA_IOCTL_BSS_LIST));
	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_BSS_LIST_GET, 0,
						 pBssList, 0, RT_DEV_PRIV_FLAGS_GET(dev));

	for (i = 0; i < IW_MAX_AP; i++) {
		if (i >=  pBssList->BssNum) /*pAd->ScanTab.BssNr) */
			break;

		addr[i].sa_family = ARPHRD_ETHER;
		pList = (pBssList->pList) + i;
		memcpy(addr[i].sa_data, pList->Bssid, MAC_ADDR_LEN);
		memcpy(extra + i * sizeof(addr[i]), &addr[i], sizeof(addr[i]));
		set_quality(pAd, &qual[i], pList); /*&pAd->ScanTab.BssEntry[i]); */
	}

	data->length = i;
	data->flags = 1;		/* signal quality present (sort of) */
	memcpy(extra + i * sizeof(addr[0]), &qual, i * sizeof(qual[i]));
	os_free_mem(addr);
	os_free_mem(pBssList->pList);
	return 0;
}

#if defined(SIOCGIWSCAN) || defined(RT_CFG80211_SUPPORT)
int rt_ioctl_siwscan(struct net_device *dev,
					 struct iw_request_info *info,
					 union iwreq_data *wreq, char *extra)
{
	VOID *pAd = NULL;
	int Status = NDIS_STATUS_SUCCESS;
	RT_CMD_STA_IOCTL_SCAN IoctlScan, *pIoctlScan = &IoctlScan;
#ifdef WPA_SUPPLICANT_SUPPORT
	struct iw_scan_req *req = (struct iw_scan_req *)extra;
#endif /* WPA_SUPPLICANT_SUPPORT */
	GET_PAD_FROM_NET_DEV(pAd, dev);
	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	/* because android will set scan and get scan when interface down */
#ifndef ANDROID_SUPPORT

	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

#endif /* ANDROID_SUPPORT */
	memset(pIoctlScan, 0, sizeof(RT_CMD_STA_IOCTL_SCAN));
#ifdef WPA_SUPPLICANT_SUPPORT
#if WIRELESS_EXT > 17
	pIoctlScan->FlgScanThisSsid = (wreq->data.length == sizeof(struct iw_scan_req) &&
								   wreq->data.flags & IW_SCAN_THIS_ESSID);
	pIoctlScan->SsidLen = req->essid_len;
	pIoctlScan->pSsid = (CHAR *)(req->essid);
#endif
	pIoctlScan->ScanType = req->scan_type;
#endif /* WPA_SUPPLICANT_SUPPORT */

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWSCAN, 0,
						 pIoctlScan, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	RT_CMD_STATUS_TRANSLATE(pIoctlScan->Status);
	Status = pIoctlScan->Status;
	return Status;
}

int rt_ioctl_giwscan(struct net_device *dev,
					 struct iw_request_info *info,
					 struct iw_point *data, char *extra)
{
	VOID *pAd = NULL;
	int i = 0, status = 0, ret;
	RTMP_STRING *current_ev = extra, *previous_ev = NULL;
	RTMP_STRING *end_buf, *current_val;
	RTMP_STRING custom[MAX_CUSTOM_LEN] = {0};
#ifndef IWEVGENIE
	unsigned char idx;
#endif /* IWEVGENIE */
	struct iw_event iwe;
	RT_CMD_STA_IOCTL_SCAN_TABLE IoctlScan, *pIoctlScan = &IoctlScan;
	UINT8 Index;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	/* because android will set scan and get scan when interface down */
#ifndef ANDROID_SUPPORT

	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

#endif /* ANDROID_SUPPORT */
	pIoctlScan->priv_flags = RT_DEV_PRIV_FLAGS_GET(dev);
	pIoctlScan->pBssTable = NULL;
	pIoctlScan->BssNr = 0;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWSCAN, 0,
							 pIoctlScan, 0,
							 RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS) {
		status = -EINVAL;
		goto go_out;
	}


	if (pIoctlScan->BssNr == 0) {
		data->length = 0;
		status = 0;
		goto go_out;
	}

#if WIRELESS_EXT >= 17

	if (data->length > 0)
		end_buf = extra + data->length;
	else
		end_buf = extra + IW_SCAN_MAX_DATA;

#else
	end_buf = extra + IW_SCAN_MAX_DATA;
#endif

	for (i = 0; i < pIoctlScan->BssNr; i++) {
		RT_CMD_STA_IOCTL_BSS_TABLE *pBssEntry = &pIoctlScan->pBssTable[i];
		BOOLEAN isGonly = FALSE;
		int rateCnt = 0;

		if (current_ev >= end_buf) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*MAC address */
		/*================================ */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = SIOCGIWAP;
		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
		memcpy(iwe.u.ap_addr.sa_data, &pIoctlScan->pBssTable[i].Bssid, ETH_ALEN);
		previous_ev = current_ev;
		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);

		if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*
		 * Protocol:
		 *	it will show scanned AP's WirelessMode .
		 *	it might be
		 *			802.11a
		 *			802.11a/n
		 *			802.11g/n
		 *			802.11b/g/n
		 *			802.11g
		 *			802.11b/g
		 */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = SIOCGIWNAME;
		if (pBssEntry->Channel > 14) {
			if (pBssEntry->has_ht_cap) {
				ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11a/n");
				if (os_snprintf_error(IFNAMSIZ, ret)) {
					MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
					status = 0;
					goto go_out;
				}
			} else {
				ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11a");
				if (os_snprintf_error(IFNAMSIZ, ret)) {
					MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
					status = 0;
					goto go_out;
				}
			}
		} else {
			/* if one of non B mode rate is set supported rate . it mean G only. */
			for (rateCnt = 0; rateCnt < pBssEntry->SupRateLen; rateCnt++) {
				/* 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate , it mean G only. */
				if (pBssEntry->SupRate[rateCnt] == 140 || pBssEntry->SupRate[rateCnt] == 146 || pBssEntry->SupRate[rateCnt] >= 152)
					isGonly = TRUE;
			}

			for (rateCnt = 0; rateCnt < pBssEntry->ExtRateLen; rateCnt++) {
				if (pBssEntry->ExtRate[rateCnt] == 140 || pBssEntry->ExtRate[rateCnt] == 146 || pBssEntry->ExtRate[rateCnt] >= 152)
					isGonly = TRUE;
			}

			if (pBssEntry->has_ht_cap) {
				if (isGonly == TRUE) {
					ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11g/n");
					if (os_snprintf_error(IFNAMSIZ, ret)) {
						MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
						status = 0;
						goto go_out;
					}
				} else {
					ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11b/g/n");
					if (os_snprintf_error(IFNAMSIZ, ret)) {
						MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
						status = 0;
						goto go_out;
					}
				}
			} else {
				if (isGonly == TRUE) {
					ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11g");
					if (os_snprintf_error(IFNAMSIZ, ret)) {
						MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
						status = 0;
						goto go_out;
					}
				} else {
					if (pBssEntry->SupRateLen == 4 && pBssEntry->ExtRateLen == 0) {
						ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11b");
						if (os_snprintf_error(IFNAMSIZ, ret)) {
							MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
							status = 0;
							goto go_out;
						}
					} else {
						ret = snprintf(iwe.u.name, IFNAMSIZ, "%s", "802.11b/g");
						if (os_snprintf_error(IFNAMSIZ, ret)) {
							MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "ShowAmpduCounter snprintf error!\n");
							status = 0;
							goto go_out;
						}
					}
				}
			}
		}

		previous_ev = current_ev;
		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);

		if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*ESSID */
		/*================================ */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = SIOCGIWESSID;
		iwe.u.data.length = pIoctlScan->pBssTable[i].SsidLen;
		iwe.u.data.flags = 1;
		previous_ev = current_ev;
		current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, (RTMP_STRING *) pIoctlScan->pBssTable[i].Ssid);

		if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*Network Type */
		/*================================ */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = SIOCGIWMODE;

		if (pIoctlScan->pBssTable[i].BssType == Ndis802_11IBSS)
			iwe.u.mode = IW_MODE_ADHOC;
		else if (pIoctlScan->pBssTable[i].BssType == Ndis802_11Infrastructure)
			iwe.u.mode = IW_MODE_INFRA;
		else
			iwe.u.mode = IW_MODE_AUTO;

		iwe.len = IW_EV_UINT_LEN;
		previous_ev = current_ev;
		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe,  IW_EV_UINT_LEN);

		if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*Channel and Frequency */
		/*================================ */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = SIOCGIWFREQ;
		{
			UCHAR ch = pIoctlScan->pBssTable[i].Channel;
			ULONG	m = 0;
			/*			MAP_CHANNEL_ID_TO_KHZ(ch, m); */

			if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
				return -EFAULT;

			RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_CHID_2_FREQ, 0,
								 (VOID *)&m, ch, RT_DEV_PRIV_FLAGS_GET(dev));
			iwe.u.freq.m = m * 100;
			iwe.u.freq.e = 1;
			iwe.u.freq.i = 0;
			previous_ev = current_ev;
			current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}
		/*Add quality statistics */
		/*================================ */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = IWEVQUAL;
		iwe.u.qual.level = 0;
		iwe.u.qual.noise = 0;
		set_quality(pAd, &iwe.u.qual, &pIoctlScan->pBssTable[i].Signal);
		current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);

		if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*Encyption key */
		/*================================ */
		memset(&iwe, 0, sizeof(iwe));
		iwe.cmd = SIOCGIWENCODE;

		if (pIoctlScan->pBssTable[i].FlgIsPrivacyOn)
			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
		else
			iwe.u.data.flags = IW_ENCODE_DISABLED;

		previous_ev = current_ev;
		Index = (iwe.u.data.flags & IW_ENCODE_INDEX) - 1;

		if (Index > 3) {
			status = -E2BIG;
			goto go_out;
		}

		current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, (char *)pIoctlScan->MainSharedKey[Index]);

		if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
			status = -E2BIG;
			goto go_out;
#else
			break;
#endif
		}

		/*Bit Rate */
		/*================================ */
		if (pIoctlScan->pBssTable[i].SupRateLen) {
			UCHAR tmpRate = pIoctlScan->pBssTable[i].SupRate[pIoctlScan->pBssTable[i].SupRateLen - 1];

			memset(&iwe, 0, sizeof(iwe));
			iwe.cmd = SIOCGIWRATE;
			current_val = current_ev + IW_EV_LCP_LEN;

			if (tmpRate == 0x82)
				iwe.u.bitrate.value =  1 * 1000000;
			else if (tmpRate == 0x84)
				iwe.u.bitrate.value =  2 * 1000000;
			else if (tmpRate == 0x8B)
				iwe.u.bitrate.value =  5.5 * 1000000;
			else if (tmpRate == 0x96)
				iwe.u.bitrate.value =  11 * 1000000;
			else
				iwe.u.bitrate.value =  (tmpRate / 2) * 1000000;

			if (pIoctlScan->pBssTable[i].ExtRateLen) {
				UCHAR tmpSupRate = (pIoctlScan->pBssTable[i].SupRate[pIoctlScan->pBssTable[i].SupRateLen - 1] & 0x7f);
				UCHAR tmpExtRate = (pIoctlScan->pBssTable[i].ExtRate[pIoctlScan->pBssTable[i].ExtRateLen - 1] & 0x7f);

				iwe.u.bitrate.value = (tmpSupRate > tmpExtRate) ? (tmpSupRate) * 500000 : (tmpExtRate) * 500000;
			}

			if (tmpRate == 0x6c && pIoctlScan->pBssTable[i].has_ht_cap) {
				int rate_count = RT_RateSize / sizeof(__s32);
				/*				HT_CAP_INFO capInfo = pIoctlScan->pBssTable[i].HtCapability.HtCapInfo; */
				int shortGI = pIoctlScan->pBssTable[i].ChannelWidth ? pIoctlScan->pBssTable[i].ShortGIfor40 : pIoctlScan->pBssTable[i].ShortGIfor20;
				int maxMCS = pIoctlScan->pBssTable[i].MCSSet ?  15 : 7;
				int rate_index = 12 + ((UCHAR)pIoctlScan->pBssTable[i].ChannelWidth * 24) +
								 ((UCHAR)shortGI * 48) + ((UCHAR)maxMCS);

				if (rate_index < 0)
					rate_index = 0;

				if (rate_index >= rate_count)
					rate_index = rate_count - 1;

				iwe.u.bitrate.value	=  ralinkrate[rate_index] * 500000;
			}

			iwe.u.bitrate.disabled = 0;
			current_val = IWE_STREAM_ADD_VALUE(info, current_ev,
											   current_val, end_buf, &iwe,
											   IW_EV_PARAM_LEN);

			if ((current_val - current_ev) > IW_EV_LCP_LEN)
				current_ev = current_val;
			else {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

#ifdef IWEVGENIE

		/*WPA IE */
		if (pIoctlScan->pBssTable[i].WpaIeLen > 0) {
			memset(&iwe, 0, sizeof(iwe));
			memset(&custom[0], 0, MAX_CUSTOM_LEN);
			memcpy(custom, &(pIoctlScan->pBssTable[i].pWpaIe[0]),
				   pIoctlScan->pBssTable[i].WpaIeLen);
			iwe.cmd = IWEVGENIE;
			iwe.u.data.length = pIoctlScan->pBssTable[i].WpaIeLen;
			current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

		/*WPA2 IE */
		if (pIoctlScan->pBssTable[i].RsnIeLen > 0) {
			memset(&iwe, 0, sizeof(iwe));
			memset(&custom[0], 0, MAX_CUSTOM_LEN);
			memcpy(custom, &(pIoctlScan->pBssTable[i].pRsnIe[0]),
				   pIoctlScan->pBssTable[i].RsnIeLen);
			iwe.cmd = IWEVGENIE;
			iwe.u.data.length = pIoctlScan->pBssTable[i].RsnIeLen;
			current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

		/*WPS IE */
		if (pIoctlScan->pBssTable[i].WpsIeLen > 0) {
			memset(&iwe, 0, sizeof(iwe));
			memset(&custom[0], 0, MAX_CUSTOM_LEN);
			memcpy(custom, &(pIoctlScan->pBssTable[i].pWpsIe[0]),
				   pIoctlScan->pBssTable[i].WpsIeLen);
			iwe.cmd = IWEVGENIE;
			iwe.u.data.length = pIoctlScan->pBssTable[i].WpsIeLen;
			current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

#else

		/*WPA IE */
		/*================================ */
		if (pIoctlScan->pBssTable[i].WpaIeLen > 0) {
			os_zero_mem(&iwe, sizeof(iwe));
			memset(&custom[0], 0, MAX_CUSTOM_LEN);
			iwe.cmd = IWEVCUSTOM;
			iwe.u.data.length = (pIoctlScan->pBssTable[i].WpaIeLen * 2) + 7;
			os_move_mem(custom, "wpa_ie=", 7);

			for (idx = 0; idx < pIoctlScan->pBssTable[i].WpaIeLen; idx++)
				sprintf(custom, "%s%02x", custom, pIoctlScan->pBssTable[i].pWpaIe[idx]);

			previous_ev = current_ev;
			current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,  custom);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

		/*WPA2 IE */
		if (pIoctlScan->pBssTable[i].RsnIeLen > 0) {
			os_zero_mem(&iwe, sizeof(iwe));
			memset(&custom[0], 0, MAX_CUSTOM_LEN);
			iwe.cmd = IWEVCUSTOM;
			iwe.u.data.length = (pIoctlScan->pBssTable[i].RsnIeLen * 2) + 7;
			os_move_mem(custom, "rsn_ie=", 7);

			for (idx = 0; idx < pIoctlScan->pBssTable[i].RsnIeLen; idx++)
				sprintf(custom, "%s%02x", custom, pIoctlScan->pBssTable[i].pRsnIe[idx]);

			previous_ev = current_ev;
			current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,  custom);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

#ifdef WSC_INCLUDED

		/*WPS IE */
		if (pIoctlScan->pBssTable[i].WpsIeLen > 0) {
			os_zero_mem(&iwe, sizeof(iwe));
			memset(&custom[0], 0, MAX_CUSTOM_LEN);
			iwe.cmd = IWEVCUSTOM;
			iwe.u.data.length = (pIoctlScan->pBssTable[i].WpsIeLen * 2) + 7;
			os_move_mem(custom, "wps_ie=", 7);

			for (idx = 0; idx < pIoctlScan->pBssTable[i].WpsIeLen; idx++)
				sprintf(custom, "%s%02x", custom, pIoctlScan->pBssTable[i].pWpsIe[idx]);

			previous_ev = current_ev;
			current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe,  custom);

			if (current_ev == previous_ev) {
#if WIRELESS_EXT >= 17
				status = -E2BIG;
				goto go_out;
#else
				break;
#endif
			}
		}

#endif /* WSC_INCLUDED */
#endif /* IWEVGENIE */
	}

	data->length = current_ev - extra;
	/*    pStaCfg->bScanReqIsFromWebUI = FALSE; */
	/*	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO ,"===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAd->ScanTab.BssNr, data->length); */

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SCAN_END, 0,
						 NULL, data->length, RT_DEV_PRIV_FLAGS_GET(dev));
go_out:

	if (pIoctlScan->pBssTable != NULL)
		os_free_mem(pIoctlScan->pBssTable);

	return status;
}
#endif

int rt_ioctl_siwessid(struct net_device *dev,
					  struct iw_request_info *info,
					  struct iw_point *data, char *essid)
{
	VOID *pAd = NULL;
	RT_CMD_STA_IOCTL_SSID IoctlEssid, *pIoctlEssid = &IoctlEssid;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (data->flags) {
		/* Includes null character. */
		if (data->length > (IW_ESSID_MAX_SIZE + 1))
			return -E2BIG;
	}

	pIoctlEssid->FlgAnySsid = data->flags;
	pIoctlEssid->SsidLen = data->length;
	pIoctlEssid->pSsid = (CHAR *)essid;
	pIoctlEssid->Status = 0;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWESSID, 0,
						 pIoctlEssid, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	RT_CMD_STATUS_TRANSLATE(pIoctlEssid->Status);
	return pIoctlEssid->Status;
}

int rt_ioctl_giwessid(struct net_device *dev,
					  struct iw_request_info *info,
					  struct iw_point *data, char *essid)
{
	VOID *pAd = NULL;
	RT_CMD_STA_IOCTL_SSID IoctlEssid, *pIoctlEssid = &IoctlEssid;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	data->flags = 1;
	NdisZeroMemory(pIoctlEssid, sizeof(RT_CMD_STA_IOCTL_SSID));
	pIoctlEssid->pSsid = (CHAR *)essid;
	pIoctlEssid->Status = 0;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWESSID, 0,
						 pIoctlEssid, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	data->length = pIoctlEssid->SsidLen;
	RT_CMD_STATUS_TRANSLATE(pIoctlEssid->Status);
	return pIoctlEssid->Status;
}

int rt_ioctl_siwnickn(struct net_device *dev,
					  struct iw_request_info *info,
					  struct iw_point *data, char *nickname)
{
	VOID *pAd = NULL;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (data->length > IW_ESSID_MAX_SIZE)
		return -EINVAL;


	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWNICKN, 0,
						 nickname, data->length, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}

int rt_ioctl_giwnickn(struct net_device *dev,
					  struct iw_request_info *info,
					  struct iw_point *data, char *nickname)
{
	VOID *pAd = NULL;
	RT_CMD_STA_IOCTL_NICK_NAME NickName, *pNickName = &NickName;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		data->length = 0;
		return -ENETDOWN;
	}

	pNickName->NameLen = data->length;
	pNickName->pName = (CHAR *)nickname;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWNICKN, 0,
						 pNickName, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	data->length = pNickName->NameLen;
	return 0;
}

int rt_ioctl_siwrts(struct net_device *dev,
					struct iw_request_info *info,
					struct iw_param *rts, char *extra)
{
	VOID *pAd = NULL;
	UINT32 val;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (rts->disabled)
		val = MAX_RTS_THRESHOLD;
	else if (rts->value > MAX_RTS_THRESHOLD)
		return -EINVAL;
	else if (rts->value == 0)
		val = MAX_RTS_THRESHOLD;
	else
		val = rts->value;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWRTS, 0,
						 NULL, val, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}

int rt_ioctl_giwrts(struct net_device *dev,
					struct iw_request_info *info,
					struct iw_param *rts, char *extra)
{
	VOID *pAd = NULL;
	USHORT RtsThreshold = 0;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWRTS, 0,
						 &RtsThreshold, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	rts->value = RtsThreshold;
	rts->disabled = (rts->value == MAX_RTS_THRESHOLD);
	rts->fixed = 1;
	return 0;
}

int rt_ioctl_siwfrag(struct net_device *dev,
					 struct iw_request_info *info,
					 struct iw_param *frag, char *extra)
{
	VOID *pAd = NULL;
	UINT16 val;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/* if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (frag->disabled)
		val = MAX_FRAG_THRESHOLD;
	else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD)
		val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */
	else if (frag->value == 0)
		val = MAX_FRAG_THRESHOLD;
	else
		return -EINVAL;

	/*pAd->CommonCfg.FragmentThreshold = val; */

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWFRAG, 0,
						 NULL, val, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}

int rt_ioctl_giwfrag(struct net_device *dev,
					 struct iw_request_info *info,
					 struct iw_param *frag, char *extra)
{
	VOID *pAd = NULL;
	USHORT FragmentThreshold = 0;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/* if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWFRAG, 0,
						 &FragmentThreshold, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	frag->value = FragmentThreshold;
	frag->disabled = (frag->value == MAX_FRAG_THRESHOLD);
	frag->fixed = 1;
	return 0;
}

#define MAX_WEP_KEY_SIZE 13
#define MIN_WEP_KEY_SIZE 5
int rt_ioctl_siwencode(struct net_device *dev,
					   struct iw_request_info *info,
					   struct iw_point *erq, char *extra)
{
	VOID *pAd = NULL;
	RT_CMD_STA_IOCTL_SECURITY IoctlSec, *pIoctlSec = &IoctlSec;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/* if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlSec->pData = (CHAR *)extra;
	pIoctlSec->length = erq->length;
	pIoctlSec->KeyIdx = (erq->flags & IW_ENCODE_INDEX) - 1;
	pIoctlSec->flags = 0;

	if (erq->flags & IW_ENCODE_DISABLED)
		pIoctlSec->flags |= RT_CMD_STA_IOCTL_SECURITY_DISABLED;

	if (erq->flags & IW_ENCODE_RESTRICTED)
		pIoctlSec->flags |= RT_CMD_STA_IOCTL_SECURITY_RESTRICTED;

	if (erq->flags & IW_ENCODE_OPEN)
		pIoctlSec->flags |= RT_CMD_STA_IOCTL_SECURITY_OPEN;

	if (erq->flags & IW_ENCODE_NOKEY)
		pIoctlSec->flags |= RT_CMD_STA_IOCTL_SECURITY_NOKEY;

	if (erq->flags & IW_ENCODE_MODE)
		pIoctlSec->flags |= RT_CMD_STA_IOCTL_SECURITY_MODE;

	pIoctlSec->Status = 0;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWENCODE, 0,
						 pIoctlSec, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	RT_CMD_STATUS_TRANSLATE(pIoctlSec->Status);
	return pIoctlSec->Status;
}

int
rt_ioctl_giwencode(struct net_device *dev,
				   struct iw_request_info *info,
				   struct iw_point *erq, char *key)
{
	/*	int kid; */
	VOID *pAd = NULL;
	RT_CMD_STA_IOCTL_SECURITY IoctlSec, *pIoctlSec = &IoctlSec;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	NdisZeroMemory(pIoctlSec, sizeof(RT_CMD_STA_IOCTL_SECURITY));
	pIoctlSec->pData = (CHAR *)key;
	pIoctlSec->KeyIdx = erq->flags & IW_ENCODE_INDEX;
	pIoctlSec->length = erq->length;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWENCODE, 0,
						 pIoctlSec, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	erq->length = pIoctlSec->length;
	erq->flags = pIoctlSec->KeyIdx;

	if (pIoctlSec->flags & RT_CMD_STA_IOCTL_SECURITY_DISABLED)
		erq->flags = RT_CMD_STA_IOCTL_SECURITY_DISABLED;

	{
		if (pIoctlSec->flags & RT_CMD_STA_IOCTL_SECURITY_ENABLED)
			erq->flags |= IW_ENCODE_ENABLED;

		if (pIoctlSec->flags & RT_CMD_STA_IOCTL_SECURITY_RESTRICTED)
			erq->flags |= IW_ENCODE_RESTRICTED;

		if (pIoctlSec->flags & RT_CMD_STA_IOCTL_SECURITY_OPEN)
			erq->flags |= IW_ENCODE_OPEN;
	}
	return 0;
}

int rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info,
					  void *w, char *extra)
{
	VOID *pAd;
	/*	POS_COOKIE pObj; */
	RTMP_STRING *this_char = extra;
	RTMP_STRING *value = NULL;
	int  Status = 0;
	RT_CMD_PARAM_SET CmdParam;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}


	if (!*this_char)
		return -EINVAL;

	value = rtstrchr(this_char, '=');

	if (value != NULL)
		*value++ = 0;

	/*check if the interface is down */
	/* if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, this_char) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	} else {

		if (!value && (strcmp(this_char, "SiteSurvey") != 0))
			return -EINVAL;
		else if (!value && (strcmp(this_char, "SiteSurvey") == 0))
			goto SET_PROC;

		/* reject setting nothing besides ANY ssid(ssidLen=0) */
		if (value && !*value && (strcmp(this_char, "SSID") != 0))
			return -EINVAL;
	}

SET_PROC:
	CmdParam.pThisChar = this_char;
	CmdParam.pValue = value;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_PARAM_SET, 0,
						 &CmdParam, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	/*	Status = RTMPSTAPrivIoctlSet(pAd, this_char, value); */
	return Status;
}

int rt_ioctl_showparam(struct net_device *dev, struct iw_request_info *info,
					   void *w, char *extra)
{
	VOID *pAd;
	/*	POS_COOKIE pObj; */
	RTMP_STRING *this_char = extra;
	RTMP_STRING *value = NULL;
	int  Status = 0;
	RT_CMD_PARAM_SET CmdParam;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	if (!*this_char)
		return -EINVAL;

	value = rtstrchr(this_char, '=');

	if (value != NULL)
		*value++ = 0;

	/*check if the interface is down */
	/* if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, this_char) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	CmdParam.pThisChar = this_char;
	CmdParam.pValue = value;

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_PARAM_SHOW, 0,
						 &CmdParam, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	return Status;
}


#ifdef WSC_STA_SUPPORT

static int
rt_private_set_wsc_u32_item(struct net_device *dev, struct iw_request_info *info,
							UINT32 *uwrq, char *extra)
{
	VOID *pAd = NULL;
	/*    int  Status=0; */
	/*    UINT32 subcmd = *uwrq; */
	/*    PWSC_PROFILE    pWscProfile = NULL; */
	/*	UINT32 value = 0; */
	RT_CMD_STA_IOCTL_WSC_U32_ITEM IoctlWscU32, *pIoctlWscU32 = &IoctlWscU32;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlWscU32->pUWrq = uwrq;
	pIoctlWscU32->Status = NDIS_STATUS_SUCCESS;
	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_IW_SET_WSC_U32_ITEM, 0,
						 pIoctlWscU32, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	RT_CMD_STATUS_TRANSLATE(pIoctlWscU32->Status);
	return pIoctlWscU32->Status;
}

static int
rt_private_set_wsc_string_item(struct net_device *dev, struct iw_request_info *info,
							   struct iw_point *dwrq, char *extra)
{
	RT_CMD_STA_IOCTL_WSC_STR_ITEM IoctlWscStr, *pIoctlWscStr = &IoctlWscStr;
	/*    int  Status=0; */
	/*    UINT32 subcmd = dwrq->flags; */
	/*    UINT32 tmpProfileIndex = (UINT32)(extra[0] - 0x30); */
	/*    UINT32 dataLen; */
	VOID *pAd = NULL;
	/*    PWSC_PROFILE    pWscProfile = NULL; */
	/*    USHORT  tmpAuth = 0, tmpEncr = 0; */
	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlWscStr->Subcmd = dwrq->flags;
	pIoctlWscStr->pData = (CHAR *)extra;
	pIoctlWscStr->length = dwrq->length;
	pIoctlWscStr->Status = RTMP_STA_IoctlHandle(pAd, NULL,
						   CMD_RTPRIV_IOCTL_STA_IW_SET_WSC_STR_ITEM, 0,
						   pIoctlWscStr, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	RT_CMD_STATUS_TRANSLATE(pIoctlWscStr->Status);
	return pIoctlWscStr->Status;
}
#endif /* WSC_STA_SUPPORT */

#ifdef WCX_SUPPORT
static int mt_private_meta_set(struct net_device *dev, struct iw_request_info *info, struct iw_point *wrq, char *extra)
{
	INT	stat = 0;
	VOID *pAd = NULL;

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "<== %s(), wrq->length = %d\n", __func__, wrq->length);
	GET_PAD_FROM_NET_DEV(pAd, dev);
	RTMP_STA_IoctlHandle(pAd, wrq, CMD_MTPRIV_IOCTL_STA_META_SET, 0, extra, IW_PRIV_SIZE_MASK, RT_DEV_PRIV_FLAGS_GET(dev));
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "%s()==>\n", __func__);
	return stat;
}

static int mt_private_meta_qurey(struct net_device *dev, struct iw_request_info *info, struct iw_point *wrq, char *extra)
{
	INT	stat = 0;
	VOID *pAd = NULL;
	RTMP_IOCTL_INPUT_STRUCT wrqin;

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "<== %s(), wrq->length = %d, wrq->pointer:%p\n", __func__, wrq->length, wrq->pointer);
	GET_PAD_FROM_NET_DEV(pAd, dev);
	wrqin.u.data.pointer = wrq->pointer;
	wrqin.u.data.length = wrq->length;
	RTMP_STA_IoctlHandle(pAd, &wrqin, CMD_MTPRIV_IOCTL_STA_META_QUERY, 0, extra, IW_PRIV_SIZE_MASK, RT_DEV_PRIV_FLAGS_GET(dev));
	wrq->length = wrqin.u.data.length;
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "%s()==>\n", __func__);
	return stat;
}

#endif /* WCX_SUPPORT */

static int
rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info,
						  struct iw_point *wrq, char *extra)
{
	INT				Status = 0;
	VOID   *pAd = NULL;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (extra == NULL) {
		wrq->length = 0;
		return -EIO;
	}

	memset(extra, 0x00, IW_PRIV_SIZE_MASK);
	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_IW_GET_STATISTICS, 0,
						 extra, IW_PRIV_SIZE_MASK, RT_DEV_PRIV_FLAGS_GET(dev));
	wrq->length = strlen(extra) + 1; /* 1: size of '\0' */
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "<== rt_private_get_statistics, wrq->length = %d\n", wrq->length);
	return Status;
}


static int
rt_private_show(struct net_device *dev, struct iw_request_info *info,
				struct iw_point *wrq, RTMP_STRING *extra)
{
	RTMP_IOCTL_INPUT_STRUCT wrqin;
	INT				Status = 0;
	VOID			*pAd;
	/*	POS_COOKIE		pObj; */
	UINT32             subcmd = wrq->flags;
	RT_CMD_STA_IOCTL_SHOW IoctlShow, *pIoctlShow = &IoctlShow;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	if (DetermineCallerInterface(dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;


	/*	pObj = (POS_COOKIE) pAd->OS_Cookie; */
	if (extra == NULL) {
		wrq->length = 0;
		return -EIO;
	}

	memset(extra, 0x00, IW_PRIV_SIZE_MASK);
	wrqin.u.data.pointer = wrq->pointer;
	wrqin.u.data.length = wrq->length;
	pIoctlShow->pData = (CHAR *)extra;
	pIoctlShow->MaxSize = IW_PRIV_SIZE_MASK;
	pIoctlShow->InfType = RT_DEV_PRIV_FLAGS_GET(dev);
	RTMP_STA_IoctlHandle(pAd, &wrqin, CMD_RTPRIV_IOCTL_SHOW, subcmd,
						 pIoctlShow, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	wrq->length = wrqin.u.data.length;
	return Status;
}

#ifdef SIOCSIWMLME
int rt_ioctl_siwmlme(struct net_device *dev,
					 struct iw_request_info *info,
					 union iwreq_data *wrqu,
					 char *extra)
{
	VOID   *pAd = NULL;
	struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer;
	/*	MLME_QUEUE_ELEM				MsgElem; */
	/*	MLME_QUEUE_ELEM				*pMsgElem = NULL; */
	/*	MLME_DISASSOC_REQ_STRUCT	DisAssocReq; */
	/*	MLME_DEAUTH_REQ_STRUCT      DeAuthReq; */
	ULONG Subcmd = 0;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "====> %s\n", __func__);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (pMlme == NULL)
		return -EINVAL;


	switch (pMlme->cmd) {
#ifdef IW_MLME_DEAUTH

	case IW_MLME_DEAUTH:
		Subcmd = RT_CMD_STA_IOCTL_IW_MLME_DEAUTH;
		break;
#endif /* IW_MLME_DEAUTH */
#ifdef IW_MLME_DISASSOC

	case IW_MLME_DISASSOC:
		Subcmd = RT_CMD_STA_IOCTL_IW_MLME_DISASSOC;
		break;
#endif /* IW_MLME_DISASSOC */

	default:
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "====> %s - Unknow Command\n", __func__);
		break;
	}

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWMLME, Subcmd,
						 NULL, pMlme->reason_code, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}
#endif /* SIOCSIWMLME */

#if WIRELESS_EXT > 17


int rt_ioctl_siwauth(struct net_device *dev,
					 struct iw_request_info *info,
					 union iwreq_data *wrqu, char *extra)
{
	VOID   *pAd = NULL;
	struct iw_param *param = &wrqu->param;
	UINT64 DefValue = param->value;
	USHORT DefFlag = (param->flags & IW_AUTH_INDEX);
	RT_CMD_STA_IOCTL_SECURITY_ADV IoctlWpa, *pIoctlWpa = &IoctlWpa;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlWpa->flags = 0;
	pIoctlWpa->value = param->value; /* default */

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "[%d] - param->value = %llu!\n", DefFlag, DefValue);

	switch (param->flags & IW_AUTH_INDEX) {
	case IW_AUTH_WPA_VERSION:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_VERSION;

		if (param->value == IW_AUTH_WPA_VERSION_WPA)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_VERSION1;
		else if (param->value == IW_AUTH_WPA_VERSION_WPA2)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_VERSION2;

		break;

	case IW_AUTH_CIPHER_PAIRWISE:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_PAIRWISE;

		if (param->value == IW_AUTH_CIPHER_NONE)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_PAIRWISE_NONE;
		else if (param->value == IW_AUTH_CIPHER_WEP40)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_PAIRWISE_WEP40;
		else if (param->value == IW_AUTH_CIPHER_WEP104)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_PAIRWISE_WEP104;
		else if (param->value == IW_AUTH_CIPHER_TKIP)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_PAIRWISE_TKIP;
		else if (param->value == IW_AUTH_CIPHER_CCMP)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_PAIRWISE_CCMP;

		break;

	case IW_AUTH_CIPHER_GROUP:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_GROUP;

		if (param->value == IW_AUTH_CIPHER_NONE)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_GROUP_NONE;
		else if (param->value == IW_AUTH_CIPHER_WEP40)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_GROUP_WEP40;
		else if (param->value == IW_AUTH_CIPHER_WEP104)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_GROUP_WEP104;
		else if (param->value == IW_AUTH_CIPHER_TKIP)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_GROUP_TKIP;
		else if (param->value == IW_AUTH_CIPHER_CCMP)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_GROUP_CCMP;

		break;

	case IW_AUTH_KEY_MGMT:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_KEY_MGMT;

		if (param->value == IW_AUTH_KEY_MGMT_802_1X)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_KEY_MGMT_1X;

		break;

	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_RX_UNENCRYPTED_EAPOL;
		break;

	case IW_AUTH_PRIVACY_INVOKED:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_PRIVACY_INVOKED;
		break;

	case IW_AUTH_DROP_UNENCRYPTED:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_DROP_UNENCRYPTED;
		break;

	case IW_AUTH_80211_AUTH_ALG:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_80211_AUTH_ALG;

		if (param->value & IW_AUTH_ALG_SHARED_KEY)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_AUTH_80211_AUTH_ALG_SHARED;
		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_AUTH_80211_AUTH_ALG_OPEN;
		else if (param->value & IW_AUTH_ALG_LEAP)
			pIoctlWpa->value = RT_CMD_STA_IOCTL_WPA_AUTH_80211_AUTH_ALG_LEAP;

		break;

	case IW_AUTH_WPA_ENABLED:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_WPA_ENABLED;
		break;

	default:
		return -EOPNOTSUPP;
	}

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWAUTH, 0,
						 pIoctlWpa, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}

int rt_ioctl_giwauth(struct net_device *dev,
					 struct iw_request_info *info,
					 union iwreq_data *wrqu, char *extra)
{
	VOID   *pAd = NULL;
	struct iw_param *param = &wrqu->param;
	UINT64 DefValue = param->value;
	RT_CMD_STA_IOCTL_SECURITY_ADV IoctlWpa, *pIoctlWpa = &IoctlWpa;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlWpa->flags = 0;
	pIoctlWpa->value = 0;

	switch (param->flags & IW_AUTH_INDEX) {
	case IW_AUTH_DROP_UNENCRYPTED:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_DROP_UNENCRYPTED;
		break;

	case IW_AUTH_80211_AUTH_ALG:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_80211_AUTH_ALG;
		break;

	case IW_AUTH_WPA_ENABLED:
		pIoctlWpa->flags = RT_CMD_STA_IOCTL_WPA_AUTH_WPA_ENABLED;
		break;

	default:
		return -EOPNOTSUPP;
	}

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWAUTH, 0,
						 pIoctlWpa, 0, RT_DEV_PRIV_FLAGS_GET(dev));

	switch (param->flags & IW_AUTH_INDEX) {
	case IW_AUTH_DROP_UNENCRYPTED:
		param->value = pIoctlWpa->value;
		break;

	case IW_AUTH_80211_AUTH_ALG:
		param->value = (pIoctlWpa->value == 0) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM;
		break;

	case IW_AUTH_WPA_ENABLED:
		param->value = pIoctlWpa->value;
		break;
	}

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "param->value = %llu!\n", DefValue);
	return 0;
}


int rt_ioctl_siwencodeext(struct net_device *dev,
						  struct iw_request_info *info,
						  union iwreq_data *wrqu,
						  char *extra)
{
	VOID   *pAd = NULL;
	struct iw_point *encoding = &wrqu->encoding;
	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
	int /* keyIdx, */ alg = ext->alg;
	RT_CMD_STA_IOCTL_SECURITY IoctlSec, *pIoctlSec = &IoctlSec;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlSec->pData = (CHAR *)ext->key;
	pIoctlSec->length = ext->key_len;
	pIoctlSec->KeyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1;

	if (alg == IW_ENCODE_ALG_NONE)
		pIoctlSec->Alg = RT_CMD_STA_IOCTL_SECURITY_ALG_NONE;
	else if (alg == IW_ENCODE_ALG_WEP)
		pIoctlSec->Alg = RT_CMD_STA_IOCTL_SECURITY_ALG_WEP;
	else if (alg == IW_ENCODE_ALG_TKIP)
		pIoctlSec->Alg = RT_CMD_STA_IOCTL_SECURITY_ALG_TKIP;
	else if (alg == IW_ENCODE_ALG_CCMP)
		pIoctlSec->Alg = RT_CMD_STA_IOCTL_SECURITY_ALG_CCMP;
	else {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_WARN, "Warning: Security type is not supported. (alg = %d)\n", alg);
		pIoctlSec->Alg = alg;
		return -EOPNOTSUPP;
	}

	pIoctlSec->ext_flags = 0;

	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
		pIoctlSec->ext_flags |= RT_CMD_STA_IOCTL_SECURTIY_EXT_SET_TX_KEY;

	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
		pIoctlSec->ext_flags |= RT_CMD_STA_IOCTL_SECURTIY_EXT_GROUP_KEY;

	if (encoding->flags & IW_ENCODE_DISABLED)
		pIoctlSec->flags = RT_CMD_STA_IOCTL_SECURITY_DISABLED;
	else
		pIoctlSec->flags = 0;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWENCODEEXT, 0,
							 pIoctlSec, 0, RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS)
		return -EINVAL;

	return 0;
}

int
rt_ioctl_giwencodeext(struct net_device *dev,
					  struct iw_request_info *info,
					  union iwreq_data *wrqu, char *extra)
{
	VOID *pAd = NULL;
	/*	PCHAR pKey = NULL; */
	struct iw_point *encoding = &wrqu->encoding;
	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
	int /* idx, */ max_key_len;
	RT_CMD_STA_IOCTL_SECURITY IoctlSec, *pIoctlSec = &IoctlSec;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "===> rt_ioctl_giwencodeext\n");

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	max_key_len = encoding->length - sizeof(*ext);

	if (max_key_len < 0)
		return -EINVAL;

	memset(ext, 0, sizeof(*ext));
	memset(pIoctlSec, 0, sizeof(RT_CMD_STA_IOCTL_SECURITY));
	pIoctlSec->KeyIdx = encoding->flags & IW_ENCODE_INDEX;
	pIoctlSec->MaxKeyLen = max_key_len;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWENCODEEXT, 0,
							 pIoctlSec, 0, RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS) {
		ext->key_len = 0;
		RT_CMD_STATUS_TRANSLATE(pIoctlSec->Status);
		return pIoctlSec->Status;
	}

	encoding->flags = pIoctlSec->KeyIdx;
	ext->key_len = pIoctlSec->length;

	if (pIoctlSec->Alg == RT_CMD_STA_IOCTL_SECURITY_ALG_NONE)
		ext->alg = IW_ENCODE_ALG_NONE;
	else if (pIoctlSec->Alg == RT_CMD_STA_IOCTL_SECURITY_ALG_WEP)
		ext->alg = IW_ENCODE_ALG_WEP;
	else if (pIoctlSec->Alg == RT_CMD_STA_IOCTL_SECURITY_ALG_TKIP)
		ext->alg = IW_ENCODE_ALG_TKIP;
	else if (pIoctlSec->Alg == RT_CMD_STA_IOCTL_SECURITY_ALG_CCMP)
		ext->alg = IW_ENCODE_ALG_CCMP;

	if (pIoctlSec->flags & RT_CMD_STA_IOCTL_SECURITY_DISABLED)
		encoding->flags |= IW_ENCODE_DISABLED;

	if (ext->key_len && pIoctlSec->pData) {
		encoding->flags |= IW_ENCODE_ENABLED;
		memcpy(ext->key, pIoctlSec->pData, ext->key_len);
	}

	return 0;
}

#ifdef SIOCSIWGENIE
int rt_ioctl_siwgenie(struct net_device *dev,
					  struct iw_request_info *info,
					  union iwreq_data *wrqu, char *extra)
{
	VOID   *pAd = NULL;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

#ifdef WPA_SUPPLICANT_SUPPORT

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWGENIE, 0,
							 extra, wrqu->data.length,
							 RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS)
		return -EINVAL;
	else
		return 0;

#endif /* WPA_SUPPLICANT_SUPPORT */
	return -EOPNOTSUPP;
}
#endif /* SIOCSIWGENIE */

int rt_ioctl_giwgenie(struct net_device *dev,
					  struct iw_request_info *info,
					  union iwreq_data *wrqu, char *extra)
{
	VOID   *pAd = NULL;
	RT_CMD_STA_IOCTL_RSN_IE IoctlRsnIe, *pIoctlRsnIe = &IoctlRsnIe;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	pIoctlRsnIe->length = wrqu->data.length;
	pIoctlRsnIe->pRsnIe = (UCHAR *)extra;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWGENIE, 0,
							 pIoctlRsnIe, 0,
							 RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS)
		return -E2BIG;

	wrqu->data.length = pIoctlRsnIe->length;
	return 0;
}

int rt_ioctl_siwpmksa(struct net_device *dev,
					  struct iw_request_info *info,
					  union iwreq_data *wrqu,
					  char *extra)
{
	VOID   *pAd = NULL;
	struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer;
	/*	INT	CachedIdx = 0, idx = 0; */
	RT_CMD_STA_IOCTL_PMA_SA IoctlPmaSa, *pIoctlPmaSa = &IoctlPmaSa;

	GET_PAD_FROM_NET_DEV(pAd, dev);

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	if (pPmksa == NULL)
		return -EINVAL;

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "===> rt_ioctl_siwpmksa\n");

	if (pPmksa->cmd == IW_PMKSA_FLUSH)
		pIoctlPmaSa->Cmd = RT_CMD_STA_IOCTL_PMA_SA_FLUSH;
	else if (pPmksa->cmd == IW_PMKSA_REMOVE)
		pIoctlPmaSa->Cmd = RT_CMD_STA_IOCTL_PMA_SA_REMOVE;
	else if (pPmksa->cmd == IW_PMKSA_ADD)
		pIoctlPmaSa->Cmd = RT_CMD_STA_IOCTL_PMA_SA_ADD;
	else
		pIoctlPmaSa->Cmd = 0;

	pIoctlPmaSa->pBssid = (UCHAR *)pPmksa->bssid.sa_data;
	pIoctlPmaSa->pPmkid = pPmksa->pmkid;
	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWPMKSA, 0,
						 pIoctlPmaSa, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	return 0;
}
#endif /* #if WIRELESS_EXT > 17 */

#ifdef DBG
static int
rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info,
					 struct iw_point *wrq, char *extra)
{
	RTMP_IOCTL_INPUT_STRUCT wrqin;
	INT Status = 0;
	VOID *pAd = NULL;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	memset(extra, 0x00, IW_PRIV_SIZE_MASK);
	wrqin.u.data.pointer = wrq->pointer;
	wrqin.u.data.length = wrq->length;
	RTMP_STA_IoctlHandle(pAd, &wrqin, CMD_RTPRIV_IOCTL_BBP, 0,
						 extra, IW_PRIV_SIZE_MASK, RT_DEV_PRIV_FLAGS_GET(dev));
	wrq->length = wrqin.u.data.length;
	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "<==rt_private_ioctl_bbp\n\n");
	return Status;
}
#endif /* DBG */

int rt_ioctl_siwrate(struct net_device *dev,
					 struct iw_request_info *info,
					 union iwreq_data *wrqu, char *extra)
{
	VOID   *pAd = NULL;
	UINT32          rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed;
	RT_CMD_RATE_SET CmdRate;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "rt_ioctl_siwrate::Network is down!\n");
		return -ENETDOWN;
	}

	MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed);
	/* rate = -1 => auto rate */
	/*   rate = X, fixed = 1 => (fixed rate X) */
	CmdRate.Rate = rate;
	CmdRate.Fixed = fixed;

	if (RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCSIWRATE, 0,
							 &CmdRate, 0,
							 RT_DEV_PRIV_FLAGS_GET(dev)) != NDIS_STATUS_SUCCESS)
		return -EOPNOTSUPP;

	return 0;
}

int rt_ioctl_giwrate(struct net_device *dev,
					 struct iw_request_info *info,
					 union iwreq_data *wrqu, char *extra)
{
	VOID   *pAd = NULL;
	/*    int rate_index = 0, rate_count = 0; */
	/*    HTTRANSMIT_SETTING ht_setting; */
	ULONG Rate = 0;

	GET_PAD_FROM_NET_DEV(pAd, dev);
	/*check if the interface is down */
	/*	if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
		return -ENETDOWN;
	}

	RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWRATE, 0,
						 &Rate, 0, RT_DEV_PRIV_FLAGS_GET(dev));
	wrqu->bitrate.value = Rate;
	wrqu->bitrate.disabled = 0;
	return 0;
}


static const iw_handler rt_handler[] = {
	(iw_handler) NULL,			            /* SIOCSIWCOMMIT */
	(iw_handler) rt_ioctl_giwname,			/* SIOCGIWNAME   */
	(iw_handler) NULL,			            /* SIOCSIWNWID   */
	(iw_handler) NULL,			            /* SIOCGIWNWID   */
	(iw_handler) rt_ioctl_siwfreq,		    /* SIOCSIWFREQ   */
	(iw_handler) rt_ioctl_giwfreq,		    /* SIOCGIWFREQ   */
	(iw_handler) rt_ioctl_siwmode,		    /* SIOCSIWMODE   */
	(iw_handler) rt_ioctl_giwmode,		    /* SIOCGIWMODE   */
	(iw_handler) NULL,		                /* SIOCSIWSENS   */
	(iw_handler) NULL,		                /* SIOCGIWSENS   */
	(iw_handler) NULL /* not used */,		/* SIOCSIWRANGE  */
	(iw_handler) rt_ioctl_giwrange,		    /* SIOCGIWRANGE  */
	(iw_handler) rt_ioctl_giwpriv,		/* SIOCSIWPRIV  for Android */
	(iw_handler) NULL /* kernel code */,    /* SIOCGIWPRIV   */
	(iw_handler) NULL /* not used */,		/* SIOCSIWSTATS  */
	(iw_handler) rt28xx_get_wireless_stats /* kernel code */,    /* SIOCGIWSTATS  */
	(iw_handler) NULL,		                /* SIOCSIWSPY    */
	(iw_handler) NULL,		                /* SIOCGIWSPY    */
	(iw_handler) NULL,				        /* SIOCSIWTHRSPY */
	(iw_handler) NULL,				        /* SIOCGIWTHRSPY */
	(iw_handler) rt_ioctl_siwap,            /* SIOCSIWAP     */
	(iw_handler) rt_ioctl_giwap,		    /* SIOCGIWAP     */
#ifdef SIOCSIWMLME
	(iw_handler) rt_ioctl_siwmlme,	        /* SIOCSIWMLME   */
#else
	(iw_handler) NULL,				        /* SIOCSIWMLME */
#endif /* SIOCSIWMLME */
	(iw_handler) rt_ioctl_iwaplist,		    /* SIOCGIWAPLIST */
#ifdef SIOCGIWSCAN
	(iw_handler) rt_ioctl_siwscan,		    /* SIOCSIWSCAN   */
	(iw_handler) rt_ioctl_giwscan,		    /* SIOCGIWSCAN   */
#else
	(iw_handler) NULL,				        /* SIOCSIWSCAN   */
	(iw_handler) NULL,				        /* SIOCGIWSCAN   */
#endif /* SIOCGIWSCAN */
	(iw_handler) rt_ioctl_siwessid,		    /* SIOCSIWESSID  */
	(iw_handler) rt_ioctl_giwessid,		    /* SIOCGIWESSID  */
	(iw_handler) rt_ioctl_siwnickn,		    /* SIOCSIWNICKN  */
	(iw_handler) rt_ioctl_giwnickn,		    /* SIOCGIWNICKN  */
	(iw_handler) NULL,				        /* -- hole --    */
	(iw_handler) NULL,				        /* -- hole --    */
	(iw_handler) rt_ioctl_siwrate,          /* SIOCSIWRATE   */
	(iw_handler) rt_ioctl_giwrate,          /* SIOCGIWRATE   */
	(iw_handler) rt_ioctl_siwrts,		    /* SIOCSIWRTS    */
	(iw_handler) rt_ioctl_giwrts,		    /* SIOCGIWRTS    */
	(iw_handler) rt_ioctl_siwfrag,		    /* SIOCSIWFRAG   */
	(iw_handler) rt_ioctl_giwfrag,		    /* SIOCGIWFRAG   */
	(iw_handler) NULL,		                /* SIOCSIWTXPOW  */
	(iw_handler) NULL,		                /* SIOCGIWTXPOW  */
	(iw_handler) NULL,		                /* SIOCSIWRETRY  */
	(iw_handler) NULL,		                /* SIOCGIWRETRY  */
	(iw_handler) rt_ioctl_siwencode,		/* SIOCSIWENCODE */
	(iw_handler) rt_ioctl_giwencode,		/* SIOCGIWENCODE */
	(iw_handler) NULL,		                /* SIOCSIWPOWER  */
	(iw_handler) NULL,		                /* SIOCGIWPOWER  */
	(iw_handler) NULL,						/* -- hole -- */
	(iw_handler) NULL,						/* -- hole -- */
#if WIRELESS_EXT > 17
	(iw_handler) rt_ioctl_siwgenie,         /* SIOCSIWGENIE  */
	(iw_handler) rt_ioctl_giwgenie,         /* SIOCGIWGENIE  */
	(iw_handler) rt_ioctl_siwauth,		    /* SIOCSIWAUTH   */
	(iw_handler) rt_ioctl_giwauth,		    /* SIOCGIWAUTH   */
	(iw_handler) rt_ioctl_siwencodeext,	    /* SIOCSIWENCODEEXT */
	(iw_handler) rt_ioctl_giwencodeext,		/* SIOCGIWENCODEEXT */
	(iw_handler) rt_ioctl_siwpmksa,         /* SIOCSIWPMKSA  */
#endif
};

static const iw_handler rt_priv_handlers[] = {
	(iw_handler) NULL, /* + 0x00 */
	(iw_handler) NULL, /* + 0x01 */
#ifndef CONFIG_AP_SUPPORT
	(iw_handler) rt_ioctl_setparam, /* + 0x02 */
#else
	(iw_handler) NULL, /* + 0x02 */
#endif /* CONFIG_AP_SUPPORT */
#ifdef DBG
	(iw_handler) rt_private_ioctl_bbp, /* + 0x03 */
#else
	(iw_handler) NULL, /* + 0x03 */
#endif
	(iw_handler) NULL, /* + 0x04 */
	(iw_handler) NULL, /* + 0x05 */
	(iw_handler) NULL, /* + 0x06 */
	(iw_handler) NULL, /* + 0x07 */
#ifdef WCX_SUPPORT
	(iw_handler) mt_private_meta_set, /* + 0x08 */
	(iw_handler) mt_private_meta_qurey, /* + 0x09 */
#else
	(iw_handler) NULL, /* + 0x08 */
	(iw_handler) rt_private_get_statistics, /* + 0x09 */
#endif
	(iw_handler) NULL, /* + 0x0A */
#ifdef WCX_SUPPORT
	(iw_handler) rt_private_get_statistics, /* + 0x0B */
#else
	(iw_handler) NULL, /* + 0x0B */
#endif
	(iw_handler) NULL, /* + 0x0C */
	(iw_handler) NULL, /* + 0x0D */
	(iw_handler) NULL, /* + 0x0E */
	(iw_handler) NULL, /* + 0x0F */
	(iw_handler) NULL, /* + 0x10 */
	(iw_handler) rt_private_show, /* + 0x11 */
	(iw_handler) rt_ioctl_showparam, /* + 0x12 */
	(iw_handler) NULL, /* + 0x13 */
#ifdef WSC_STA_SUPPORT
	(iw_handler) rt_private_set_wsc_u32_item, /* + 0x14 */
#else
	(iw_handler) NULL, /* + 0x14 */
#endif /* WSC_STA_SUPPORT */
#ifdef WCX_SUPPORT
	(iw_handler) rt_private_get_statistics, /* + 0x15 */
#else
	(iw_handler) NULL, /* + 0x15 */
#endif
#ifdef WSC_STA_SUPPORT
	(iw_handler) rt_private_set_wsc_string_item, /* + 0x16 */
#else
	(iw_handler) NULL, /* + 0x16 */
#endif /* WSC_STA_SUPPORT */
	(iw_handler) NULL, /* + 0x17 */
	(iw_handler) NULL, /* + 0x18 */
};

const struct iw_handler_def rt28xx_iw_handler_def = {
#define	N(a)	(ARRAY_SIZE(a))
	.standard	= (iw_handler *) rt_handler,
	.num_standard	= sizeof(rt_handler) / sizeof(iw_handler),
#ifdef CONFIG_WEXT_PRIV
	.private	= (iw_handler *) rt_priv_handlers,
	.num_private		= N(rt_priv_handlers),
	.private_args	= (struct iw_priv_args *) privtab,
	.num_private_args	= N(privtab),
#endif /* #ifdef CONFIG_WEXT_PRIV */
#if IW_HANDLER_VERSION >= 7
	.get_wireless_stats = rt28xx_get_wireless_stats,
#endif
};

INT rt28xx_sta_ioctl(void *net_dev_obj, void *rq, INT cmd) /* snowpin for ap/sta */
{
	/* POS_COOKIE pObj; */
	struct net_device *net_dev;
	VOID *pAd = NULL;
	struct iwreq *wrqin = (struct iwreq *) rq;
	RTMP_IOCTL_INPUT_STRUCT rt_wrq, *wrq = &rt_wrq;
	/* BOOLEAN StateMachineTouched = FALSE; */
	INT Status = NDIS_STATUS_SUCCESS;
	USHORT subcmd;
	UINT32 org_len;

	net_dev = (struct net_device *)net_dev_obj;
	GET_PAD_FROM_NET_DEV(pAd, net_dev);
	if (pAd == NULL) {
		/* if 1st open fail, pAd will be free; */
		/*   So the net_dev->priv will be NULL in 2rd open */
		return -ENETDOWN;
	}

	if (wrqin == NULL) {
		MTWF_DBG(NULL, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_DEBUG, "INFO::wrqin is null!\n");
		return Status;
	}

	wrq->u.data.pointer = wrqin->u.data.pointer;
	wrq->u.data.length = wrqin->u.data.length;
	org_len = wrq->u.data.length;

	if (DetermineCallerInterface(net_dev, pAd) != NDIS_STATUS_SUCCESS)
		return -EFAULT;

	/*check if the interface is down */
	/*    if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) */
	if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS) {
		if (wrqin->u.data.pointer == NULL)
			return Status;

		if (cmd != RTPRIV_IOCTL_SET) {
			MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "INFO::Network is down!\n");
			return -ENETDOWN;
		}
	}

	switch (cmd) {
#ifdef CONFIG_QA

	case RTPRIV_IOCTL_ATE: {
		/* ATE is always controlled by ra0 */
		RTMP_COM_IoctlHandle(pAd, wrq, CMD_RTPRIV_IOCTL_ATE, 0, wrqin->ifr_name, 0);
	}
	break;
#endif

	case SIOCGIFHWADDR:
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_INFO, "IOCTL::SIOCGIFHWADDR\n");
		/*			memcpy(wrqin->u.name, pAd->CurrentAddress, ETH_ALEN); */
		RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIFHWADDR,
							 0, wrqin->u.name, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		break;

	case SIOCGIWNAME: {
		return -EOPNOTSUPP;
	}

	case SIOCGIWESSID: { /*Get ESSID */
		struct iw_point *essid = &wrqin->u.essid;

		rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer);
		break;
	}

	case SIOCSIWESSID: { /*Set ESSID */
		struct iw_point	*essid = &wrqin->u.essid;

		rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer);
		break;
	}

	case SIOCSIWNWID:   /* set network id (the cell) */
	case SIOCGIWNWID:   /* get network id */
		Status = -EOPNOTSUPP;
		break;

	case SIOCSIWFREQ: { /*set channel/frequency (Hz) */
		struct iw_freq *freq = &wrqin->u.freq;

		rt_ioctl_siwfreq(net_dev, NULL, freq, NULL);
		break;
	}

	case SIOCGIWFREQ: { /* get channel/frequency (Hz) */
		struct iw_freq *freq = &wrqin->u.freq;

		rt_ioctl_giwfreq(net_dev, NULL, freq, NULL);
		break;
	}

	case SIOCSIWNICKN: { /*set node name/nickname */
		/*struct iw_point *data=&wrq->u.data; */
		/*rt_ioctl_siwnickn(net_dev, NULL, data, NULL); */
		break;
	}

	case SIOCGIWNICKN: { /*get node name/nickname */
		RT_CMD_STA_IOCTL_NICK_NAME NickName, *pNickName = &NickName;
		CHAR nickname[IW_ESSID_MAX_SIZE + 1] = {0};
		struct iw_point	*erq = NULL;

		erq = &wrqin->u.data;
		pNickName->NameLen = IW_ESSID_MAX_SIZE + 1;
		pNickName->pName = (CHAR *)nickname;
		RTMP_STA_IoctlHandle(pAd, NULL, CMD_RTPRIV_IOCTL_STA_SIOCGIWNICKN, 0,
							 pNickName, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		erq->length = pNickName->NameLen; /*strlen((RTMP_STRING *) pAd->nickname); */
		Status = copy_to_user(erq->pointer, nickname, erq->length);
		break;
	}

	case SIOCGIWRATE:   /*get default bit rate (bps) */
		rt_ioctl_giwrate(net_dev, NULL, &wrqin->u, NULL);
		break;

	case SIOCSIWRATE:  /*set default bit rate (bps) */
		rt_ioctl_siwrate(net_dev, NULL, &wrqin->u, NULL);
		break;

	case SIOCGIWRTS: { /* get RTS/CTS threshold (bytes) */
		struct iw_param *rts = &wrqin->u.rts;

		rt_ioctl_giwrts(net_dev, NULL, rts, NULL);
		break;
	}

	case SIOCSIWRTS: { /*set RTS/CTS threshold (bytes) */
		struct iw_param *rts = &wrqin->u.rts;

		rt_ioctl_siwrts(net_dev, NULL, rts, NULL);
		break;
	}

	case SIOCGIWFRAG: { /*get fragmentation thr (bytes) */
		struct iw_param *frag = &wrqin->u.frag;

		rt_ioctl_giwfrag(net_dev, NULL, frag, NULL);
		break;
	}

	case SIOCSIWFRAG: { /*set fragmentation thr (bytes) */
		struct iw_param *frag = &wrqin->u.frag;

		rt_ioctl_siwfrag(net_dev, NULL, frag, NULL);
		break;
	}

	case SIOCGIWENCODE: { /*get encoding token & mode */
		struct iw_point *erq = &wrqin->u.encoding;

		if (erq)
			rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer);

		break;
	}

	case SIOCSIWENCODE: { /*set encoding token & mode */
		struct iw_point *erq = &wrqin->u.encoding;

		if (erq)
			rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer);

		break;
	}

	case SIOCGIWAP: {   /*get access point MAC addresses */
		struct sockaddr *ap_addr = &wrqin->u.ap_addr;

		rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data);
		break;
	}

	case SIOCSIWAP: { /*set access point MAC addresses */
		struct sockaddr *ap_addr = &wrqin->u.ap_addr;

		rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data);
		break;
	}

	case SIOCGIWMODE: { /*get operation mode */
		__u32 *mode = &wrqin->u.mode;

		rt_ioctl_giwmode(net_dev, NULL, mode, NULL);
		break;
	}

	case SIOCSIWMODE: { /*set operation mode */
		__u32 *mode = &wrqin->u.mode;

		rt_ioctl_siwmode(net_dev, NULL, mode, NULL);
		break;
	}

	case SIOCGIWSENS:   /*get sensitivity (dBm) */
	case SIOCSIWSENS:	/*set sensitivity (dBm) */
	case SIOCGIWPOWER:  /*get Power Management settings */
	case SIOCSIWPOWER:  /*set Power Management settings */
	case SIOCGIWTXPOW:  /*get transmit power (dBm) */
	case SIOCSIWTXPOW:  /*set transmit power (dBm) */
	case SIOCGIWRANGE:	/*Get range of parameters */
	case SIOCGIWRETRY:	/*get retry limits and lifetime */
	case SIOCSIWRETRY:	/*set retry limits and lifetime */
		Status = -EOPNOTSUPP;
		break;

	case RT_PRIV_IOCTL:
#ifdef RT_CFG80211_ANDROID_PRIV_LIB_SUPPORT
			/* YF: Android Private Lib Entry */
			rt_android_private_command_entry(pAd, net_dev, (struct ifreq *)rq, cmd);
		break;
#endif /* RT_CFG80211_ANDROID_PRIV_LIB_SUPPORT */

	case RT_PRIV_IOCTL_EXT:
		subcmd = wrqin->u.data.flags;
		Status = RTMP_STA_IoctlHandle(pAd, wrq, CMD_RT_PRIV_IOCTL, subcmd,
									  NULL, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		break;

	case SIOCGIWPRIV:
		if (wrqin->u.data.pointer) {
#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE)
			if (access_ok(VERIFY_WRITE, wrqin->u.data.pointer, sizeof(privtab)) != TRUE)
#else
			if (access_ok(wrqin->u.data.pointer, sizeof(privtab)) != TRUE)
#endif
				break;

			if ((ARRAY_SIZE(privtab)) <= wrq->u.data.length) {
				wrqin->u.data.length = ARRAY_SIZE(privtab);

				if (copy_to_user(wrqin->u.data.pointer, privtab, sizeof(privtab)))
					Status = -EFAULT;
			} else
				Status = -E2BIG;
		}

		break;

	case RTPRIV_IOCTL_SET:
#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE)
		if (access_ok(VERIFY_READ, wrqin->u.data.pointer, wrqin->u.data.length) != TRUE)
#else
		if (access_ok(wrqin->u.data.pointer, wrqin->u.data.length) != TRUE)
#endif
			break;

		return rt_ioctl_setparam(net_dev, NULL, NULL, wrqin->u.data.pointer);

	case RTPRIV_IOCTL_STA_SHOW: /* snowpin for ap/sta */
#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE)
		if (access_ok(VERIFY_READ, wrqin->u.data.pointer, wrqin->u.data.length) != TRUE)
#else
		if (access_ok(wrqin->u.data.pointer, wrqin->u.data.length) != TRUE)
#endif
			break;

		return rt_ioctl_showparam(net_dev, NULL, NULL, wrqin->u.data.pointer);

	case RTPRIV_IOCTL_GSITESURVEY:
		RTMP_STA_IoctlHandle(pAd, wrq, CMD_RTPRIV_IOCTL_SITESURVEY_GET, 0,
							 NULL, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		/*			RTMPIoctlGetSiteSurvey(pAd, wrq); */
		break;
#ifdef DBG

	case RTPRIV_IOCTL_MAC:
		RTMP_STA_IoctlHandle(pAd, wrq, CMD_RTPRIV_IOCTL_MAC, 0,
							 NULL, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		/*			RTMPIoctlMAC(pAd, wrq); */
		break;

	case RTPRIV_IOCTL_E2P:
		RTMP_STA_IoctlHandle(pAd, wrq, CMD_RTPRIV_IOCTL_E2P, 0,
							 NULL, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		/*			RTMPIoctlE2PROM(pAd, wrq); */
		break;
#ifdef RTMP_RF_RW_SUPPORT

	case RTPRIV_IOCTL_RF:
		RTMP_STA_IoctlHandle(pAd, wrq, CMD_RTPRIV_IOCTL_RF, 0,
							 NULL, 0, RT_DEV_PRIV_FLAGS_GET(net_dev));
		/*			RTMPIoctlRF(pAd, wrq); */
		break;
#endif /* RTMP_RF_RW_SUPPORT */
#endif /* DBG */

	case SIOCETHTOOL:
		break;

	default:
		MTWF_DBG(pAd, DBG_CAT_CFG, DBG_SUBCAT_ALL, DBG_LVL_ERROR, "IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd);
		Status = -EOPNOTSUPP;
		break;
	}

	/*    if(StateMachineTouched) // Upper layer sent a MLME-related operations */
	/* RTMP_MLME_HANDLER(pAd); */

	if (Status != 0) {
		RT_CMD_STATUS_TRANSLATE(Status);
	} else {
		/*
		 *	If wrq length is modified, we reset the lenght of origin wrq;
		 *
		 *	Or we can not modify it because the address of wrq->u.data.length
		 *	maybe same as other union field, ex: iw_range, etc.
		 *
		 *	if the length is not changed but we change it, the value for other
		 *	union will also be changed, this is not correct.
		 */
		if (wrq->u.data.length != org_len)
			wrqin->u.data.length = wrq->u.data.length;
	}

	return Status;
}

